Concentric Corner Geometry
GeometryReader in Scripting is the equivalent of SwiftUI’s GeometryReader. It provides layout information about the container in which its content is placed, including size, safe-area insets, and (on supported systems) container corner insets.
This component is essential for building responsive layouts that depend on the parent container’s geometry.
GeometryProxy
When GeometryReader constructs its child content, it injects a GeometryProxy instance into the children callback. This proxy exposes real-time layout information about the container.
GeometryProxy Properties
1. size
The actual size of the container during layout.
Size structure
Use this property when calculating adaptive layout behavior, such as scaling, alignment, or proportional spacing.
2. safeAreaInsets
Represents the safe-area insets of the current container. This ensures content does not overlap with the device notch, home indicator, or other system UI elements.
Common use cases
- Adjusting content away from the screen edges
- Implementing custom navigation bars or toolbars
- Ensuring layout compatibility across devices
3. containerCornerInsets (iOS 26.0+)
Available only on iOS 26+. Provides layout insets corresponding to the physical or visual rounded corners of the container.
Use cases
- Adapting UI for windowed environments
- Handling rounded container corners (Stage Manager, split view, floating scenes)
- Performing precision layout aligned to dynamic corner geometry
If the platform does not support it, the value will be null.
GeometryReader Component
Props
Behavior
- GeometryReader occupies the available space in its parent.
- During layout, it computes size, safe-area insets, and corner insets.
- It passes these values to the
children(proxy)callback. - The returned VirtualNode content is laid out using these values.
This behavior matches SwiftUI’s GeometryReader model.
Example: Centered Content
Example: Adjusting Layout by Safe Area
Example (iOS 26+): Using containerCornerInsets
Best Practices
- Use GeometryReader only when needed, as it creates a flexible layout container.
- Prefer using it for adaptive, responsive layouts where container size matters.
- Avoid placing complex or deeply nested views inside GeometryReader unless required.
Concentric corner radii (iOS 27.0+)
proxy.concentricCornerRadii returns { topLeading, bottomLeading, bottomTrailing, topTrailing }, in points. It describes the concentric rectangle corner radii appropriate for the current geometry. It is null on earlier systems and when SwiftUI has no corner information. It is a layout snapshot and updates alongside size and safeAreaInsets; it does not retain a native GeometryProxy or expose arbitrary-frame queries.
frame(space): coordinate frames (iOS 17+)
proxy.frame(space) maps to SwiftUI GeometryProxy.frame(in:), returning {x,y,width,height} in points. It measures the GeometryReader container in the selected space. Global follows SwiftUI semantics and is not guaranteed to equal physical screen coordinates.
Local is always available. Declare other spaces with coordinateSpaces. Omitting it or passing an empty array measures local only, avoiding unnecessary position-driven rebuilds. Named spaces use a nonempty {named: "panel"} tag so names cannot collide with reserved tokens. Assign coordinateSpace="panel" to an ancestor, rather than only to the reader's child.
"scrollView" selects the innermost containing scroll view. The axis variant selects the innermost containing scroll view that allows scrolling along that axis. Provide the matching ancestor; missing ancestors preserve native behavior, without synthesizing a zero rectangle or an existence check.
Invalid arguments, empty names and undeclared spaces throw. Results are read-only and duplicate requests are deduplicated. Frames belong to this layout build: retaining an old proxy retains the old snapshot, not a live native handle. Position changes rebuild children even when size is unchanged; no per-frame callback rate is promised. Transforms can make frame dimensions differ from size. Avoid feedback loops that repeatedly change the measured layout. Prefer dedicated scroll APIs for scroll observation.
Run index.tsx and tap Move / Reset to compare local, panel and global y while size stays unchanged.
